package cn.edu.sjtu.se.dslab.component.design.generate;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import cn.edu.sjtu.se.dslab.component.data.AvionicsEquipment;
import cn.edu.sjtu.se.dslab.component.data.util.DataComponentUtil;
import cn.edu.sjtu.se.dslab.component.dp.parse.DesignPatternInstanceBean;
import cn.edu.sjtu.se.dslab.component.dp.parse.Property;
import cn.edu.sjtu.se.dslab.project.Project;
import cn.edu.sjtu.se.dslab.service.IAvionicsEquipmentService;
import cn.edu.sjtu.se.dslab.service.IDataComponentService;
import cn.edu.sjtu.se.dslab.service.IDomainEntityService;
import cn.edu.sjtu.se.dslab.service.IInterfaceMethodService;

/**
 * 
 * @author thinker
 * 
 */
@Service("ioDpcCodeGenerator")
public class IODpcCodeGenerator extends DesignPatternCodeGenerator {
	private static final Logger logger = Logger
			.getLogger(IODpcCodeGenerator.class);

	private static final String EQUIPMENT = "equipment";
	private static final String BUS_TYPE = "bus_type";
	private static final String EQUIPMENT_NUMBER = "equipment_number";

//	private static final String CDSF_IO_C_FILE_NAME = "CDSF_IO.c";
	private static final String CDSF_IO_H_FILE_NAME = "CDSF_IO.h";
//	private static final String CDSF_INJECTION_IO_C_FILE_NAME = "CDSF_Injection_IO.c";
//	private static final String CDSF_INJECTION_IO_H_FILE_NAME = "CDSF_Injection_IO.h";
//
//	private static final String CDSF_IO_C_TEMPLATE_NAME = "cdsf_io_c.vm";
	private static final String CDSF_IO_H_TEMPLATE_NAME = "CDSF_IO_h.vm";
//	private static final String CDSF_INJECTION_IO_C_TEMPLATE_NAME = "cdsf_injection_io_c.vm";
//	private static final String CDSF_INJECTION_IO_H_TEMPLATE_NAME = "cdsf_injection_io_h.vm";
	
	private static final String CDSF_CONFIGS_IO_C_TEMPLATE_NAME = "CDSF_Configs_IO_c.vm";
	private static final String CDSF_CONFIGS_IO_C_FILE_NAME = "CDSF_Configs_IO.c";
//	
	private static final String DEVICE_H_TEMPLATE_NAME = "device_h.vm";
	private static final String DEVICE_C_TEMPLATE_NAME = "device_c.vm";
	private static final String DEVICE_BUS_H_TEMPLATE_NAME = "device_bus_h.vm";
	private static final String DEVICE_BUS_C_TEMPLATE_NAME = "device_bus_c.vm";

	@Resource(name = "dataComponentService")
	IDataComponentService dataComponentService;

	@Resource(name = "domainEntityService")
	IDomainEntityService domainEntityService;

	@Resource(name = "avionicsEquipmentService")
	IAvionicsEquipmentService avionicsEquipmentService;

	@Resource(name = "dataComponentUtil")
	DataComponentUtil dataComponentUtil;

	@Resource(name = "interfaceMethodService")
	IInterfaceMethodService interfaceMethodService;

	public IODpcCodeGenerator() {
		super();
	}

	@Override
	public void generateCode(String targetDirPath, Project project, 
			DesignPatternInstanceBean... dpiBean) throws IOException {

//		List<Map<String, Property>> instances = new ArrayList<Map<String, Property>>();
//		for (Map<String, Property> instance : dpiBean[0].getInstances()) {
//			instances.add(getInstanceValue(instance));
//		}
//		inputData("instances", instances);

		// Get all the Bus
//		Set<String> busSet = new HashSet<String>();
//		for (Property p : dpiBean[0].getPropertyByName(BUS_TYPE)) {
//			busSet.add(p.getValue());
//		}
//		inputData("buses", busSet);
		Map<String, List<String>> devices = new HashMap<String, List<String>>();
		
		List<Map<String, Property>> instances = dpiBean[0].getInstances();
		for (Map<String, Property> instance : dpiBean[0].getInstances()) {
			String equipmentUri = instance.get(EQUIPMENT).getValue();
			AvionicsEquipment equipment = avionicsEquipmentService
					.getAvionicsEquipmentByUri(equipmentUri);
			
			String busUri = instance.get(BUS_TYPE).getValue();
			AvionicsEquipment bus = avionicsEquipmentService
					.getAvionicsEquipmentByUri(busUri);
			
			if(devices.get(bus.getName()) == null){
				List<String> d = new ArrayList<String>();
				d.add(equipment.getName());
				devices.put(bus.getName(), d);
			}else{
				devices.get(bus.getName()).add(equipment.getName());
			}
			
			StringBuilder sourceFilePath = new StringBuilder(targetDirPath);
			sourceFilePath.append("/Devices/").append("Device_").append(equipment.getName()).append(".c");
			StringBuilder headerFilePath = new StringBuilder(targetDirPath);
			headerFilePath.append("/Devices/").append("Device_").append(equipment.getName()).append(".h");
			
			inputData("deviceName", equipment.getName());
			generateCodeFile(sourceFilePath.toString(), DEVICE_C_TEMPLATE_NAME);
			generateCodeFile(headerFilePath.toString(), DEVICE_H_TEMPLATE_NAME);
		}
		
		for (Entry<String, List<String>> entry : devices.entrySet()){
			String busName = entry.getKey();
			inputData("deviceName", busName);
			inputData("devices", entry.getValue());
			
			StringBuilder busSrcFilePath = new StringBuilder(targetDirPath);
			busSrcFilePath.append("/Devices/").append("Device_").append(busName).append(".c");
			StringBuilder busHeaderFilePath = new StringBuilder(targetDirPath);
			busHeaderFilePath.append("/Devices/").append("Device_").append(busName).append(".h");
			
			generateCodeFile(busSrcFilePath.toString(), DEVICE_BUS_C_TEMPLATE_NAME);
			generateCodeFile(busHeaderFilePath.toString(), DEVICE_BUS_H_TEMPLATE_NAME);
			
			
		}

//		// generate the CDSF_IO.c
//		StringBuffer cdsfIOCFilePath = new StringBuffer(targetDirPath);
//		cdsfIOCFilePath.append("/CASF/").append(CDSF_IO_C_FILE_NAME);
//		generateCodeFile(cdsfIOCFilePath.toString(), CDSF_IO_C_TEMPLATE_NAME);
//
		// generate CDSF_IO.c
//		StringBuffer cdsfInjectionIOFilePath = new StringBuffer(targetDirPath);
//		cdsfInjectionIOFilePath.append("/casf/").append(
//				CDSF_INJECTION_IO_C_FILE_NAME);
//		generateCodeFile(cdsfInjectionIOFilePath.toString(),
//				CDSF_INJECTION_IO_C_TEMPLATE_NAME);
//		
//		//generate CDSF_IO.h
		inputData("buses", devices.keySet());
		StringBuffer cdsfIOHFilePath = new StringBuffer(targetDirPath);
		cdsfIOHFilePath.append("/CASF/").append(CDSF_IO_H_FILE_NAME);
		generateCodeFile(cdsfIOHFilePath.toString(), CDSF_IO_H_TEMPLATE_NAME);
//		
		//generate CDSF_Configs_IO.c
		StringBuffer cdsfConfigsIOSrcFilePath = new StringBuffer(targetDirPath);
		cdsfConfigsIOSrcFilePath.append("/CASFConfigs/").append(CDSF_CONFIGS_IO_C_FILE_NAME);
		generateCodeFile(cdsfConfigsIOSrcFilePath.toString(), CDSF_CONFIGS_IO_C_TEMPLATE_NAME);

	}

	private Map<String, Property> getInstanceValue(
			Map<String, Property> instance) {
		AvionicsEquipment bus = avionicsEquipmentService
				.getAvionicsEquipmentByUri(instance.get(BUS_TYPE).getValue());
		logger.info("Inner Bus name:" + bus.getName());
		instance.get(BUS_TYPE).setValue(bus.getName());

		for (Entry<String, Property> e : instance.entrySet()) {
			logger.info("[" + e.getKey() + "]=" + e.getValue().getValue());
		}

		logger.info("Equipment Uri:" + instance.get(EQUIPMENT).getValue());
		AvionicsEquipment equipment = avionicsEquipmentService
				.getAvionicsEquipmentByUri(instance.get(EQUIPMENT).getValue());
		logger.info("Equipment name:" + equipment.getName());
		instance.get(EQUIPMENT).setValue(equipment.getName());
		return instance;
	}

}
